#ifndef __INILOAD_H
#define __INILOAD_H

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#ifndef INILOAD_NAME_MAXLEN
#define INILOAD_NAME_MAXLEN 128
#endif

#ifndef INILOAD_INITIAL_CAP
#define INILOAD_INITIAL_CAP 8
#endif

/* Forward declaration */
typedef struct ini_file ini_file;

/* Functions */
#ifdef __cplusplus
extern "C" {
#endif

/**
 * @brief Parses an INI file and returns a pointer to an object containing
 * the parsed data.
 *
 * @param path Path to the INI file
 * @return Pointer to an ini_file struct containing the parsed data or NULL if
 * there was an error parsing or dynamically allocating the memory.
 * @note Keys without a section are assigned to a section with an empty name
 * ("\0").
 */
ini_file *ini_load(const char *path);

/**
 * @brief Returns the total number of sections in the INI file.
 *
 * @param ini Pointer to a loaded INI file.
 * @return Total number of sections in the INI file.
 * @note Keys without a section are assigned to a section with an empty name
 * ("\0") which also counts as a section.
 */
size_t ini_num_sections(ini_file *ini);

/**
 * @brief Checks if a loaded INI file has a section with a given name.
 *
 * @param ini Pointer to a loaded INI file.
 * @param section_name Name of the section.
 * @return 1 if a section with the give name is present, 0 otherwise.
 */
int ini_has_section(ini_file *ini, const char *section_name);

/**
 * @brief Returns the total number of keys in a section with a given name.
 *
 * @param ini Pointer to a loaded INI file.
 * @param section_name Name of the section.
 * @return Total number of keys in the section with the given name.
 * @note If a section with the given name does not exist then 0 is returned.
 */
size_t ini_num_keys(ini_file *ini, const char *section_name);

/**
 * @brief Checks if a section with a given has a key with a given name.
 *
 * @param ini Pointer to a loaded INI file.
 * @param section_name Name of the section.
 * @param key_name Name of the key.
 * @return 1 if a key with the give name is present in the section, 0 if either
 * a key with the given name is not present in the section, or if the section
 * itself is not present.
 */
int ini_has_key(ini_file *ini, const char *section_name, const char *key_name);

/**
 * @brief Retrieves an integer-typed key's value.
 *
 * @param ini Pointer to a loaded INI file.
 * @param section_name Name of the section.
 * @param key_name Name of the key.
 * @param default_val Default value that is returned if the key's value is of a
 * different type or if the key or the section doesn't exist.
 * @return The key's value or the default value.
 */
int ini_get_int(ini_file *ini, const char *section_name, const char *key_name,
                int default_val);

/**
 * @brief Retrieves an float-typed key's value.
 *
 * @param ini Pointer to a loaded INI file.
 * @param section_name Name of the section.
 * @param key_name Name of the key.
 * @param default_val Default value that is returned if the key's value is of a
 * different type or if the key or the section doesn't exist.
 * @return The key's value or the default value.
 */
float ini_get_float(ini_file *ini, const char *section_name,
                    const char *key_name, float default_val);

/**
 * @brief Retrieves an string-typed key's value.
 *
 * @param ini Pointer to a loaded INI file.
 * @param section_name Name of the section.
 * @param key_name Name of the key.
 * @param default_val Default value that is returned if the key's value is of a
 * different type or if the key or the section doesn't exist.
 * @return The key's value or the default value.
 */
char *ini_get_string(ini_file *ini, const char *section_name,
                     const char *key_name, char *default_val);

/**
 * @brief Frees all dynamically allocated memory that is used by the parsed
 * INI file.
 *
 * @param ini Pointer to a loaded INI file.
 */
void ini_free(ini_file *ini);

#ifdef __cplusplus
}
#endif

#endif /* INILOAD_H */

